home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / BBS-Archive / Comm / AmiTCP30b2.lha / src / amitcp / netinet / tcp_usrreq.c < prev    next >
C/C++ Source or Header  |  1993-08-12  |  15KB  |  569 lines

  1. RCS_ID_C="$Id: tcp_usrreq.c,v 1.10 1993/06/04 11:16:15 jraja Exp $";
  2. /*
  3.  * Copyright (c) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>,
  4.  *                    Helsinki University of Technology, Finland.
  5.  *                    All rights reserved.
  6.  *
  7.  * HISTORY
  8.  * $Log: tcp_usrreq.c,v $
  9.  * Revision 1.10  1993/06/04  11:16:15  jraja
  10.  * Fixes for first public release.
  11.  *
  12.  * Revision 1.9  1993/05/17  00:16:44  ppessi
  13.  * Changed RCS version. Added rcsid.
  14.  *
  15.  * Revision 1.8  1993/04/24  17:48:13  jraja
  16.  * Removed MCLBYTES, set default buffer size to 8 kilobytes.
  17.  *
  18.  * Revision 1.7  93/04/19  02:39:50  02:39:50  ppessi (Pekka Pessi)
  19.  * Default socket buffer space made bigger
  20.  * 
  21.  * Revision 1.6  93/04/05  19:06:44  19:06:44  jraja (Jarno Tapio Rajahalme)
  22.  * Changed storage of the spl functions  return values to type spl_t.
  23.  * Added include for conf.h to every .c file.
  24.  * 
  25.  * Revision 1.5  93/03/16  08:28:51  08:28:51  jraja (Jarno Tapio Rajahalme)
  26.  * Made PRU_SENSE (stat) unsupported on AmiTCP
  27.  * 
  28.  * Revision 1.4  93/03/05  21:09:45  21:09:45  jraja (Jarno Tapio Rajahalme)
  29.  * Fixed includes (again).
  30.  * 
  31.  * Revision 1.3  93/03/03  21:28:27  21:28:27  jraja (Jarno Tapio Rajahalme)
  32.  * Moved various data definitions from header files to here.
  33.  * 
  34.  * Revision 1.2  93/02/26  09:59:47  09:59:47  jraja (Jarno Tapio Rajahalme)
  35.  * Made this compile with ANSI C (added prototypes).
  36.  * Changed so_linger to so_linger.tv_sec, since so_linger changed from short
  37.  * 
  38.  * Revision 1.1  92/11/17  16:31:09  16:31:09  jraja (Jarno Tapio Rajahalme)
  39.  * Initial revision
  40.  *
  41.  */
  42.  
  43. /*
  44.  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
  45.  * All rights reserved.
  46.  *
  47.  * Redistribution and use in source and binary forms, with or without
  48.  * modification, are permitted provided that the following conditions
  49.  * are met:
  50.  * 1. Redistributions of source code must retain the above copyright
  51.  *    notice, this list of conditions and the following disclaimer.
  52.  * 2. Redistributions in binary form must reproduce the above copyright
  53.  *    notice, this list of conditions and the following disclaimer in the
  54.  *    documentation and/or other materials provided with the distribution.
  55.  * 3. All advertising materials mentioning features or use of this software
  56.  *    must display the following acknowledgement:
  57.  *    This product includes software developed by the University of
  58.  *    California, Berkeley and its contributors.
  59.  * 4. Neither the name of the University nor the names of its contributors
  60.  *    may be used to endorse or promote products derived from this software
  61.  *    without specific prior written permission.
  62.  *
  63.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  64.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  65.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  66.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  67.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  68.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  69.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  70.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  71.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  72.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  73.  * SUCH DAMAGE.
  74.  *
  75.  *    @(#)tcp_usrreq.c    7.15 (Berkeley) 6/28/90
  76.  */
  77.  
  78. #include <conf.h>
  79.  
  80. #include <sys/param.h>
  81. #include <sys/systm.h>
  82. #include <sys/malloc.h>
  83. #include <sys/mbuf.h>
  84. #include <sys/socket.h>
  85. #include <sys/socketvar.h>
  86. #include <sys/protosw.h>
  87. #include <sys/errno.h>
  88. #include <sys/synch.h>
  89.  
  90. #include <net/if.h>
  91. #include <net/route.h>
  92.  
  93. #include <netinet/in.h>
  94. #include <netinet/in_systm.h>
  95. #include <netinet/ip.h>
  96. #include <netinet/in_pcb.h>
  97. #include <netinet/ip_var.h>
  98. #include <netinet/tcp.h>
  99. #include <netinet/tcp_fsm.h>
  100. #include <netinet/tcp_seq.h>
  101. #include <netinet/tcp_timer.h>
  102. #include <netinet/tcp_var.h>
  103. #include <netinet/tcpip.h>
  104. #include <netinet/tcp_debug.h>
  105.  
  106. #include <netinet/tcp_usrreq_protos.h>
  107. #include <netinet/tcp_output_protos.h>
  108. #include <netinet/tcp_subr_protos.h>
  109. #include <netinet/tcp_timer_protos.h>
  110. #include <netinet/in_protos.h>
  111. #include <netinet/in_pcb_protos.h>
  112. #include <kern/uipc_socket2_protos.h>
  113. #include <netinet/tcp_debug_protos.h>
  114. #include <netinet/ip_output_protos.h>
  115.  
  116. struct    inpcb tcb = { 0 };        /* head of queue of active tcpcb's */
  117. struct    tcpstat tcpstat = { 0 };    /* tcp statistics */
  118. tcp_seq    tcp_iss = { 0 };        /* tcp initial send seq # */
  119. #ifdef KPROF
  120. int    tcp_acounts[TCP_NSTATES][PRU_NREQ] = { 0 };
  121. #endif
  122. /* 
  123.  * Configurable variables
  124.  */
  125. u_long    tcp_sendspace = 8 * 1024;
  126. u_long    tcp_recvspace = 8 * 1024;
  127.  
  128. /*
  129.  * TCP protocol interface to socket abstraction.
  130.  */
  131. extern    char *tcpstates[];
  132. struct    tcpcb *tcp_newtcpcb();
  133.  
  134. /*
  135.  * Process a TCP user request for TCP tb.  If this is a send request
  136.  * then m is the mbuf chain of send data.  If this is a timer expiration
  137.  * (called from the software clock routine), then timertype tells which timer.
  138.  */
  139. int
  140. tcp_usrreq(so, req, m, nam, control)
  141.     struct socket *so;
  142.     int req;
  143.     struct mbuf *m, *nam, *control;
  144. {
  145.     register struct inpcb *inp;
  146.     register struct tcpcb *tp;
  147.     spl_t s;
  148.     int error = 0;
  149.     int ostate;
  150.  
  151.     if (req == PRU_CONTROL)
  152.         return (in_control(so, (int)m, (caddr_t)nam,
  153.             (struct ifnet *)control));
  154.     if (control && control->m_len) {
  155.         m_freem(control);
  156.         if (m)
  157.             m_freem(m);
  158.         return (EINVAL);
  159.     }
  160.  
  161.     s = splnet();
  162.     inp = sotoinpcb(so);
  163.     /*
  164.      * When a TCP is attached to a socket, then there will be
  165.      * a (struct inpcb) pointed at by the socket, and this
  166.      * structure will point at a subsidary (struct tcpcb).
  167.      */
  168.     if (inp == 0 && req != PRU_ATTACH) {
  169.         splx(s);
  170.         return (EINVAL);        /* XXX */
  171.     }
  172.     if (inp) {
  173.         tp = intotcpcb(inp);
  174.         /* WHAT IF TP IS 0? */
  175. #ifdef KPROF
  176.         tcp_acounts[tp->t_state][req]++;
  177. #endif
  178.         ostate = tp->t_state;
  179.     } else
  180.         ostate = 0;
  181.     switch (req) {
  182.  
  183.     /*
  184.      * TCP attaches to socket via PRU_ATTACH, reserving space,
  185.      * and an internet control block.
  186.      */
  187.     case PRU_ATTACH:
  188.         if (inp) {
  189.             error = EISCONN;
  190.             break;
  191.         }
  192.         error = tcp_attach(so);
  193.         if (error)
  194.             break;
  195.         if ((so->so_options & SO_LINGER) && so->so_linger.tv_sec == 0)
  196.             so->so_linger.tv_sec = TCP_LINGERTIME;
  197.         tp = sototcpcb(so);
  198.         break;
  199.  
  200.     /*
  201.      * PRU_DETACH detaches the TCP protocol from the socket.
  202.      * If the protocol state is non-embryonic, then can't
  203.      * do this directly: have to initiate a PRU_DISCONNECT,
  204.      * which may finish later; embryonic TCB's can just
  205.      * be discarded here.
  206.      */
  207.     case PRU_DETACH:
  208.         if (tp->t_state > TCPS_LISTEN)
  209.             tp = tcp_disconnect(tp);
  210.         else
  211.             tp = tcp_close(tp);
  212.         break;
  213.  
  214.     /*
  215.      * Give the socket an address.
  216.      */
  217.     case PRU_BIND:
  218.         error = in_pcbbind(inp, nam);
  219.         if (error)
  220.             break;
  221.         break;
  222.  
  223.     /*
  224.      * Prepare to accept connections.
  225.      */
  226.     case PRU_LISTEN:
  227.         if (inp->inp_lport == 0)
  228.             error = in_pcbbind(inp, (struct mbuf *)0);
  229.         if (error == 0)
  230.             tp->t_state = TCPS_LISTEN;
  231.         break;
  232.  
  233.     /*
  234.      * Initiate connection to peer.
  235.      * Create a template for use in transmissions on this connection.
  236.      * Enter SYN_SENT state, and mark socket as connecting.
  237.      * Start keep-alive timer, and seed output sequence space.
  238.      * Send initial segment on connection.
  239.      */
  240.     case PRU_CONNECT:
  241.         if (inp->inp_lport == 0) {
  242.             error = in_pcbbind(inp, (struct mbuf *)0);
  243.             if (error)
  244.                 break;
  245.         }
  246.         error = in_pcbconnect(inp, nam);
  247.         if (error)
  248.             break;
  249.         tp->t_template = tcp_template(tp);
  250.         if (tp->t_template == 0) {
  251.             in_pcbdisconnect(inp);
  252.             error = ENOBUFS;
  253.             break;
  254.         }
  255.         soisconnecting(so);
  256.         tcpstat.tcps_connattempt++;
  257.         tp->t_state = TCPS_SYN_SENT;
  258.         tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
  259.         tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2;
  260.         tcp_sendseqinit(tp);
  261.         error = tcp_output(tp);
  262.         break;
  263.  
  264.     /*
  265.      * Create a TCP connection between two sockets.
  266.      */
  267.     case PRU_CONNECT2:
  268.         error = EOPNOTSUPP;
  269.         break;
  270.  
  271.     /*
  272.      * Initiate disconnect from peer.
  273.      * If connection never passed embryonic stage, just drop;
  274.      * else if don't need to let data drain, then can just drop anyways,
  275.      * else have to begin TCP shutdown process: mark socket disconnecting,
  276.      * drain unread data, state switch to reflect user close, and
  277.      * send segment (e.g. FIN) to peer.  Socket will be really disconnected
  278.      * when peer sends FIN and acks ours.
  279.      *
  280.      * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
  281.      */
  282.     case PRU_DISCONNECT:
  283.         tp = tcp_disconnect(tp);
  284.         break;
  285.  
  286.     /*
  287.      * Accept a connection.  Essentially all the work is
  288.      * done at higher levels; just return the address
  289.      * of the peer, storing through addr.
  290.      */
  291.     case PRU_ACCEPT: {
  292.         struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
  293.  
  294.         nam->m_len = sizeof (struct sockaddr_in);
  295.         sin->sin_family = AF_INET;
  296.         sin->sin_len = sizeof(*sin);
  297.         sin->sin_port = inp->inp_fport;
  298.         sin->sin_addr = inp->inp_faddr;
  299.         break;
  300.         }
  301.  
  302.     /*
  303.      * Mark the connection as being incapable of further output.
  304.      */
  305.     case PRU_SHUTDOWN:
  306.         socantsendmore(so);
  307.         tp = tcp_usrclosed(tp);
  308.         if (tp)
  309.             error = tcp_output(tp);
  310.         break;
  311.  
  312.     /*
  313.      * After a receive, possibly send window update to peer.
  314.      */
  315.     case PRU_RCVD:
  316.         (void) tcp_output(tp);
  317.         break;
  318.  
  319.     /*
  320.      * Do a send by putting data in output queue and updating urgent
  321.      * marker if URG set.  Possibly send more data.
  322.      */
  323.     case PRU_SEND:
  324.         sbappend(&so->so_snd, m);
  325.         error = tcp_output(tp);
  326.         break;
  327.  
  328.     /*
  329.      * Abort the TCP.
  330.      */
  331.     case PRU_ABORT:
  332.         tp = tcp_drop(tp, ECONNABORTED);
  333.         break;
  334.  
  335.     case PRU_SENSE:
  336. #ifdef AMITCP
  337.                 /* stat not supported in AMITCP */
  338.         error = EOPNOTSUPP;
  339.         break;
  340. #else
  341.         ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
  342.         (void) splx(s);
  343.         return (0);
  344. #endif
  345.     case PRU_RCVOOB:
  346.         if ((so->so_oobmark == 0 &&
  347.             (so->so_state & SS_RCVATMARK) == 0) ||
  348.             so->so_options & SO_OOBINLINE ||
  349.             tp->t_oobflags & TCPOOB_HADDATA) {
  350.             error = EINVAL;
  351.             break;
  352.         }
  353.         if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) {
  354.             error = EWOULDBLOCK;
  355.             break;
  356.         }
  357.         m->m_len = 1;
  358.         *mtod(m, caddr_t) = tp->t_iobc;
  359.         if (((int)nam & MSG_PEEK) == 0)
  360.             tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);
  361.         break;
  362.  
  363.     case PRU_SENDOOB:
  364.         if (sbspace(&so->so_snd) < -512) {
  365.             m_freem(m);
  366.             error = ENOBUFS;
  367.             break;
  368.         }
  369.         /*
  370.          * According to RFC961 (Assigned Protocols),
  371.          * the urgent pointer points to the last octet
  372.          * of urgent data.  We continue, however,
  373.          * to consider it to indicate the first octet
  374.          * of data past the urgent section.
  375.          * Otherwise, snd_up should be one lower.
  376.          */
  377.         sbappend(&so->so_snd, m);
  378.         tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
  379.         tp->t_force = 1;
  380.         error = tcp_output(tp);
  381.         tp->t_force = 0;
  382.         break;
  383.  
  384.     case PRU_SOCKADDR:
  385.         in_setsockaddr(inp, nam);
  386.         break;
  387.  
  388.     case PRU_PEERADDR:
  389.         in_setpeeraddr(inp, nam);
  390.         break;
  391.  
  392.     /*
  393.      * TCP slow timer went off; going through this
  394.      * routine for tracing's sake.
  395.      */
  396.     case PRU_SLOWTIMO:
  397.         tp = tcp_timers(tp, (int)nam);
  398.         req |= (int)nam << 8;        /* for debug's sake */
  399.         break;
  400.  
  401.     default:
  402.         panic("tcp_usrreq");
  403.     }
  404.     if (tp && (so->so_options & SO_DEBUG))
  405.         tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req);
  406.     splx(s);
  407.     return (error);
  408. }
  409.  
  410. int
  411. tcp_ctloutput(op, so, level, optname, mp)
  412.     int op;
  413.     struct socket *so;
  414.     int level, optname;
  415.     struct mbuf **mp;
  416. {
  417.     int error = 0;
  418.     struct inpcb *inp = sotoinpcb(so);
  419.     register struct tcpcb *tp = intotcpcb(inp);
  420.     register struct mbuf *m;
  421.  
  422.     if (level != IPPROTO_TCP)
  423.         return (ip_ctloutput(op, so, level, optname, mp));
  424.  
  425.     switch (op) {
  426.  
  427.     case PRCO_SETOPT:
  428.         m = *mp;
  429.         switch (optname) {
  430.  
  431.         case TCP_NODELAY:
  432.             if (m == NULL || m->m_len < sizeof (int))
  433.                 error = EINVAL;
  434.             else if (*mtod(m, int *))
  435.                 tp->t_flags |= TF_NODELAY;
  436.             else
  437.                 tp->t_flags &= ~TF_NODELAY;
  438.             break;
  439.  
  440.         case TCP_MAXSEG:    /* not yet */
  441.         default:
  442.             error = EINVAL;
  443.             break;
  444.         }
  445.         if (m)
  446.             (void) m_free(m);
  447.         break;
  448.  
  449.     case PRCO_GETOPT:
  450.         *mp = m = m_get(M_WAIT, MT_SOOPTS);
  451.         m->m_len = sizeof(int);
  452.  
  453.         switch (optname) {
  454.         case TCP_NODELAY:
  455.             *mtod(m, int *) = tp->t_flags & TF_NODELAY;
  456.             break;
  457.         case TCP_MAXSEG:
  458.             *mtod(m, int *) = tp->t_maxseg;
  459.             break;
  460.         default:
  461.             error = EINVAL;
  462.             break;
  463.         }
  464.         break;
  465.     }
  466.     return (error);
  467. }
  468.  
  469. /*
  470.  * Attach TCP protocol to socket, allocating
  471.  * internet protocol control block, tcp control block,
  472.  * bufer space, and entering LISTEN state if to accept connections.
  473.  */
  474. int
  475. tcp_attach(so)
  476.     struct socket *so;
  477. {
  478.     register struct tcpcb *tp;
  479.     struct inpcb *inp;
  480.     int error;
  481.  
  482.     if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
  483.         error = soreserve(so, tcp_sendspace, tcp_recvspace);
  484.         if (error)
  485.             return (error);
  486.     }
  487.     error = in_pcballoc(so, &tcb);
  488.     if (error)
  489.         return (error);
  490.     inp = sotoinpcb(so);
  491.     tp = tcp_newtcpcb(inp);
  492.     if (tp == 0) {
  493.         int nofd = so->so_state & SS_NOFDREF;    /* XXX */
  494.  
  495.         so->so_state &= ~SS_NOFDREF;    /* don't free the socket yet */
  496.         in_pcbdetach(inp);
  497.         so->so_state |= nofd;
  498.         return (ENOBUFS);
  499.     }
  500.     tp->t_state = TCPS_CLOSED;
  501.     return (0);
  502. }
  503.  
  504. /*
  505.  * Initiate (or continue) disconnect.
  506.  * If embryonic state, just send reset (once).
  507.  * If in ``let data drain'' option and linger null, just drop.
  508.  * Otherwise (hard), mark socket disconnecting and drop
  509.  * current input data; switch states based on user close, and
  510.  * send segment to peer (with FIN).
  511.  */
  512. struct tcpcb *
  513. tcp_disconnect(tp)
  514.     register struct tcpcb *tp;
  515. {
  516.     struct socket *so = tp->t_inpcb->inp_socket;
  517.  
  518.     if (tp->t_state < TCPS_ESTABLISHED)
  519.         tp = tcp_close(tp);
  520.     else if ((so->so_options & SO_LINGER) && so->so_linger.tv_sec == 0)
  521.         tp = tcp_drop(tp, 0);
  522.     else {
  523.         soisdisconnecting(so);
  524.         sbflush(&so->so_rcv);
  525.         tp = tcp_usrclosed(tp);
  526.         if (tp)
  527.             (void) tcp_output(tp);
  528.     }
  529.     return (tp);
  530. }
  531.  
  532. /*
  533.  * User issued close, and wish to trail through shutdown states:
  534.  * if never received SYN, just forget it.  If got a SYN from peer,
  535.  * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
  536.  * If already got a FIN from peer, then almost done; go to LAST_ACK
  537.  * state.  In all other cases, have already sent FIN to peer (e.g.
  538.  * after PRU_SHUTDOWN), and just have to play tedious game waiting
  539.  * for peer to send FIN or not respond to keep-alives, etc.
  540.  * We can let the user exit from the close as soon as the FIN is acked.
  541.  */
  542. struct tcpcb *
  543. tcp_usrclosed(tp)
  544.     register struct tcpcb *tp;
  545. {
  546.  
  547.     switch (tp->t_state) {
  548.  
  549.     case TCPS_CLOSED:
  550.     case TCPS_LISTEN:
  551.     case TCPS_SYN_SENT:
  552.         tp->t_state = TCPS_CLOSED;
  553.         tp = tcp_close(tp);
  554.         break;
  555.  
  556.     case TCPS_SYN_RECEIVED:
  557.     case TCPS_ESTABLISHED:
  558.         tp->t_state = TCPS_FIN_WAIT_1;
  559.         break;
  560.  
  561.     case TCPS_CLOSE_WAIT:
  562.         tp->t_state = TCPS_LAST_ACK;
  563.         break;
  564.     }
  565.     if (tp && tp->t_state >= TCPS_FIN_WAIT_2)
  566.         soisdisconnected(tp->t_inpcb->inp_socket);
  567.     return (tp);
  568. }
  569.